package impl

import (
	"context"
	"errors"
	"fmt"
	"go-caipu/pkg/infra/log"
	"go-caipu/pkg/services/dto"
	"go-caipu/pkg/services/schedule"
	"go-caipu/pkg/services/schedule/models"
	"gorm.io/gorm"
	"time"
)

type store interface {
	GetSysJobPage(ctx context.Context, cmd schedule.GetSysJobPageCommand) (data []schedule.SysJob, num int64, err error)
	Get(ctx context.Context, cmd schedule.GetSysJobCommand) (schedule.SysJob, error)
	Insert(ctx context.Context, cmd schedule.SysJob) (jobId int, err error)
	Update(ctx context.Context, cmd schedule.SysJob) error
	// UpdateEntryId(ctx context.Context, cmd schedule.SysJob) error
	Remove(ctx context.Context, cmd schedule.RemoveSysJobCommand) error
	InsertJobLog(ctx context.Context, cmd *models.SysJobLog) error
	UpdateJobLog(ctx context.Context, cmd *models.SysJobLog) error
	GetJobLogPage(ctx context.Context, cmd schedule.GetSysJobLogPageCmd) (result []models.SysJobLog, num int64, err error)
}
type sqlStore struct {
	db     *gorm.DB
	logger log.Logger
}

func ProvideStore(db *gorm.DB) sqlStore {
	return sqlStore{
		db:     db,
		logger: log.New("dept.store"),
	}
}

func (s sqlStore) GetSysJobPage(ctx context.Context, cmd schedule.GetSysJobPageCommand) (result []schedule.SysJob, num int64, err error) {
	var items []models.SysJob
	err = s.db.Model(&models.SysJob{}).Scopes(
		dto.MakeCondition(cmd.GetNeedSearch()),
		dto.Paginate(cmd.GetPageSize(), cmd.GetPageIndex()),
	).Find(&items).Limit(-1).Offset(-1).Count(&num).Error
	if err != nil {
		return
	}
	for _, v := range items {
		result = append(result, ConvertToDTO(v))
	}
	return
}
func ConvertToDTO(model models.SysJob) schedule.SysJob {
	result := schedule.SysJob{

		JobId:          model.JobId,
		JobName:        model.JobName,
		JobGroup:       model.JobGroup,
		JobType:        model.JobType,
		CronExpression: model.CronExpression,
		InvokeTarget:   model.InvokeTarget,
		Args:           model.Args,
		MisfirePolicy:  model.MisfirePolicy,
		Concurrent:     model.Concurrent,
		Status:         model.Status,
		EntryId:        model.EntryId,
		ControlBy:      model.ControlBy,
		CreatedAt:      model.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt:      model.UpdatedAt.Format("2006-01-02 15:04:05"),
	}

	return result
}
func (s sqlStore) Get(ctx context.Context, cmd schedule.GetSysJobCommand) (result schedule.SysJob, err error) {
	var data models.SysJob
	err = s.db.Model(&data).First(&data, cmd.JobId).Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New(fmt.Sprintf("JobId=%d record Not found", cmd.JobId))
		return
	}
	if err != nil {
		s.logger.Log(fmt.Sprintf("get  sysjob=%d  error:%s", cmd.JobId, err.Error()))
		return
	}
	return ConvertToDTO(data), nil
}
func ConvertToDT(model schedule.SysJob, cmd *models.SysJob) {

	cmd.JobId = model.JobId
	cmd.JobName = model.JobName
	cmd.JobGroup = model.JobGroup
	cmd.JobType = model.JobType
	cmd.CronExpression = model.CronExpression
	cmd.InvokeTarget = model.InvokeTarget
	cmd.Args = model.Args
	cmd.MisfirePolicy = model.MisfirePolicy
	cmd.Concurrent = model.Concurrent
	cmd.Status = model.Status
	cmd.EntryId = model.EntryId
}

func (s sqlStore) Insert(ctx context.Context, cmd schedule.SysJob) (jobId int, err error) {
	tx := s.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	var data models.SysJob
	ConvertToDT(cmd, &data)
	data.CreatedAt = time.Now()
	data.CreateBy = cmd.CreateBy

	err = tx.Create(&data).Error
	if err != nil {
		s.logger.Log(fmt.Sprintf("insert  sysjob  error:%s", err.Error()))
		return 0, err
	}
	return data.JobId, nil
}

func (s sqlStore) Update(ctx context.Context, cmd schedule.SysJob) (err error) {
	tx := s.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	//查询当前部门名称是否存在
	var data models.SysJob
	err = s.db.Model(&data).First(&data, cmd.JobId).Error
	if err != nil {
		s.logger.Log(fmt.Sprintf("check SysJob id=%d is exists error:%s", cmd.JobId, err.Error()))
		return err
	}
	ConvertToDT(cmd, &data)
	data.UpdatedAt = time.Now()
	data.UpdateBy = cmd.UpdateBy
	err = tx.Save(&data).Error
	if err != nil {
		s.logger.Log(fmt.Sprintf("update  sysjob  error:%s", err.Error()))
		return err
	}
	return nil
}

//	func (s sqlStore) UpdateEntryId(ctx context.Context, cmd schedule.SysJob) error {
//		return s.db.Model(&dto.SysJob{}).Where("job_id = ?", cmd.JobId).Update("entry_id", cmd.EntryId).Error
//	}
func (s sqlStore) Remove(ctx context.Context, cmd schedule.RemoveSysJobCommand) (err error) {
	tx := s.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	var data models.SysJob
	err = tx.Model(&models.SysJob{}).Delete(&data, cmd.Ids).Error
	if err != nil {
		return err
	}
	return
}
func (s sqlStore) InsertJobLog(ctx context.Context, cmd *models.SysJobLog) error {
	return s.db.Create(cmd).Error
}
func (s sqlStore) UpdateJobLog(ctx context.Context, cmd *models.SysJobLog) error {
	return s.db.Save(cmd).Error
}
func (s sqlStore) GetJobLogPage(ctx context.Context, cmd schedule.GetSysJobLogPageCmd) (result []models.SysJobLog, num int64, err error) {
	var items []models.SysJobLog
	err = s.db.Model(&models.SysJobLog{}).Scopes(
		dto.MakeCondition(cmd.GetNeedSearch()),
		dto.Paginate(cmd.GetPageSize(), cmd.GetPageIndex()),
	).Find(&items).Limit(-1).Offset(-1).Count(&num).Error
	return items, num, err
}
